package fr.gdi.android.news;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.ref.SoftReference;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import fr.gdi.android.news.utils.AsyncImageLoader;
import fr.gdi.android.news.utils.Constants;
import fr.gdi.android.news.utils.Constants.Preferences;
import fr.gdi.android.news.utils.Constants.Provider;
import fr.gdi.android.news.utils.Constants.URI;
import fr.gdi.android.news.utils.IOUtils;
import fr.gdi.android.news.utils.PreferenceUtils;
import fr.gdi.android.news.utils.Utils;
import fr.gdi.android.news.widgets.ScrollableNewsWidget;

public class SimpleNewsEntry implements Comparable<SimpleNewsEntry>
{
    
    private static final String DATE_FIELD = Provider.Columns.NEWS_DATE.toString();
    
    public static enum FontSize 
    {
        Big, 
        Small,
        Normal
    }
    
    public String url;
    public String title;
    
    private int headlineColor = -1;
    
    private Map<String, String> map = new HashMap<String, String>();
    
    public SimpleNewsEntry(Map<String, String> map)
    {
        this.map = map;
    }
    
    public SimpleNewsEntry(String url, String title)
    {
        this.url = url;
        this.title = title;
    }
    
    public Object[] toArray(final Context ctx, final Integer appWidgetId)
    {
        Object[] res = new Object[Provider.PROJECTION_APPWIDGETS.length];
        
        final Set<String> images = new TreeSet<String>();
        for (int u = 0, l = res.length; u < l; u++)
        {
            String col = Provider.PROJECTION_APPWIDGETS[u];
            CharSequence val = map.get(col);
            
            val = !TextUtils.isEmpty(val) ? val.toString().trim() : "";
            
            CharSequence value = val;
            
            if (TextUtils.equals(col, Provider.Columns.NEWS_DESCRIPTION.toString()))
            {
                value = getSummary(ctx, appWidgetId, val);
            }
            
            if (TextUtils.equals(col, Provider.Columns.NEWS_DATE.toString()))
            {
                if ( !TextUtils.isEmpty(val) )
                {
                    try
                    {
                        Date d = DatabaseHelper.SQL_DATE_FORMAT_WITH_YEAR.parse(val.toString());
                        val = DatabaseHelper.SQL_DATE_FORMAT.format(d);
                    }
                    catch (ParseException e)
                    {
                        //swallow
                        Log.w(this.getClass().getName(), "ParseException (with year): " + val);
                    }
                }
                value = getFooterValue(ctx, appWidgetId, val + " ");
            }
            
            if (TextUtils.equals(col, Provider.Columns.NEWS_TITLE.toString()))
            {
                value = getTitle(ctx, appWidgetId, val);
            }
            
            if (TextUtils.equals(col, Provider.Columns.NEWS_AUTHOR.toString()))
            {
                if ( !TextUtils.isEmpty(val) && val.length() > 25)
                {
                    val = val.subSequence(0, 22).toString() + "...";
                }
                value = getFooterValue(ctx, appWidgetId, val);
            }
            
            if (!TextUtils.equals(col, Provider.Columns.NEWS_IMAGE_URL.toString()) )
            {
                value = Utils.replaceEntities(value);
            }
            
            res[u] = value;
            
            if (TextUtils.equals(col, Provider.Columns.NEWS_IMAGE_URL.toString()) )
            {
                boolean showImages = PreferenceUtils.getBooleanPreference(ctx, Preferences.SHOW_IMAGES, appWidgetId);
                
                if (showImages)
                {
                    if ( !TextUtils.isEmpty(value) )
                    {
                        SoftReference<Bitmap> ref = IOUtils.getCachedImage(ctx, value.toString(), appWidgetId);
                        if (ref != null)
                        {
                            Bitmap bmp = ref.get();
                            if (bmp != null)
                            {
                                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                bmp.compress(Bitmap.CompressFormat.PNG, 85, baos);
                                res[u] = baos.toByteArray();
                            }
                        }
                        else
                        {
                            images.add(value.toString());
                        }
                    }
                }
            }
            
        }
        
        if ( images.size() > 0 ) 
        {
            final Integer[] appWidgetIds = new Integer[] { appWidgetId };
            AsyncImageLoader.ImageLoadedListener listener = new AsyncImageLoader.ImageLoadedListener() {
                int count = images.size();
                
                @Override
                public void imageLoaded(Bitmap imageBitmap)
                {
                    count--;
                    if (count == 0)
                    {
                        ScrollableNewsWidget.setDownloading(ctx, appWidgetIds, false);
                        //ScrollableNewsWidget.redraw(ctx, appWidgetId);
                        Uri widgetUri = URI.CONTENT_URI_WIDGET_FEEDS.buildUpon().appendEncodedPath(Integer.toString(appWidgetId)).build();
                        ctx.getContentResolver().notifyChange(widgetUri, null);
                    }
                }
            };
            
            //ScrollableNewsWidget.setDownloading(ctx, appWidgetIds, true);
            //new AsyncImageLoader(ctx).loadImage(images, listener);
        }
        
        return res;
    }
    
    private CharSequence getTitle(Context ctx, Integer appWidgetId, CharSequence val)
    {
        int color = headlineColor;
        if ( this.headlineColor == -1 ) 
        {
            color = PreferenceUtils.getIntPreference(ctx, Preferences.HEADLINE_COLOR, Color.WHITE, appWidgetId);
        }
        boolean b = PreferenceUtils.getBooleanPreference(ctx, Preferences.CAPITALIZE_KEY, appWidgetId);
        String size = PreferenceUtils.getStringPreference(ctx, Preferences.HEADLINE_SIZE, appWidgetId, SimpleNewsEntry.FontSize.Normal.toString());
        CharSequence text = b ? val.toString().toUpperCase() : val;
        boolean reg = PreferenceUtils.getBooleanPreference(ctx, Preferences.REGULAR_HEADLINE, appWidgetId);
        text = reg ? text : ("<b>" + text + "</b>");
        return getStyledString(color, text, size);
    }
    
    private CharSequence getFooterValue(Context ctx, Integer appWidgetId, CharSequence val)
    {
        int footerColor = PreferenceUtils.getIntPreference(ctx, Preferences.FOOTER_COLOR, Color.WHITE, appWidgetId);
        boolean b = PreferenceUtils.getBooleanPreference(ctx, Preferences.CAPITALIZE_KEY, appWidgetId);
        String size = PreferenceUtils.getStringPreference(ctx, Preferences.FOOTER_SIZE, appWidgetId, SimpleNewsEntry.FontSize.Normal.toString());
        return getStyledString(footerColor, b ? val.toString().toUpperCase() : val, size);
    }
    
    private CharSequence getSummary(Context ctx, Integer appWidgetId, CharSequence val)
    {
        int descriptionColor = PreferenceUtils.getIntPreference(ctx, Preferences.SUMMARY_COLOR, Color.WHITE, appWidgetId);
        int cropLength = PreferenceUtils.getCropLength(ctx, appWidgetId);
        if (cropLength > 0)
        {
            String[] parts = TextUtils.split(val.toString(), " ");
            if (cropLength < parts.length)
            {
                StringBuilder descriptionBuilder = new StringBuilder();
                for (int i = 0; i < cropLength; i++)
                {
                    if (i > 0) descriptionBuilder.append(" ");
                    descriptionBuilder.append(parts[i]);
                }
                
                val = descriptionBuilder.append(" >>").toString();
            }
        }
        else if (cropLength < 0)
        {
            return "";
        }
        
        String size = PreferenceUtils.getStringPreference(ctx, Preferences.SUMMARY_SIZE, appWidgetId, SimpleNewsEntry.FontSize.Normal.toString());
        return getStyledString(descriptionColor, val, size);
    }
    
    private String getStyledString(int color, CharSequence value, String size)
    {
        String v = "<font color='" + Utils.colorToRgbHexString(color) + "'>" + value + "</font>";
        
        if ( !TextUtils.isEmpty(size) && !TextUtils.equals("normal", size.toLowerCase()) )
        {
            v.replaceAll("'", "&rsquo;");
            v = new StringBuilder().append("<").append(size.toLowerCase()).append(">")
                                   .append(v)
                                   .append("</").append(size.toLowerCase()).append(">")
                                   .toString();
        }
        
        try
        {
            return new String(v.getBytes("UTF-8"));
        }
        catch (UnsupportedEncodingException e)
        {
            Log.e(Constants.PACKAGE, "Failed to convert to UTF-8. Returning default encoded value instead.", e);
            return v;
        }
    }
    
    public void setHeadlineColor(int headlineColor)
    {
        this.headlineColor = headlineColor;
    }
    
    @Override
    public int compareTo(SimpleNewsEntry s)
    {
        String ds2 = s.map.get(DATE_FIELD);
        String ds1 = map.get(DATE_FIELD);
        
        if ( TextUtils.isEmpty(ds1) )
        {
            return TextUtils.isEmpty(ds2) ? 0 : -1;
        }
        
        if ( TextUtils.isEmpty(ds2) ) return 1;
        
        
        try
        {
            Date d1 = DatabaseHelper.SQL_DATE_FORMAT_WITH_YEAR.parse(ds1);
            Date d2 = DatabaseHelper.SQL_DATE_FORMAT_WITH_YEAR.parse(ds2);
            return d2.compareTo(d1);
        }
        catch (ParseException e)
        {
            return 0;
        }
    }
    
    public Object get(String key)
    {
        return map.get(key);
    }
}
